﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.IO;
using System.Threading;

namespace TicketSellingServer
{
    public class TicketSellingService : ITicketSellingService
    {
        public SellerFlightsList SearchTickets(string date, string source, string destination)
        {
            SellerFlightsList searchList = new SellerFlightsList();

            //search doesnt change server state, so we need reader lock here
            ServerData.ticketDataBaseLock.AcquireReaderLock(Timeout.Infinite);
            foreach (var ticket in ServerData.ticketDataBase)
            {
                if (ticket.Date.Equals(date)
                    && ticket.Source.Equals(source)
                    && ticket.Destination.Equals(destination))
                {
                    if (ticket.AvailiableSeats > 0)
                    {
                        SellerFlightInfo currTicket = new SellerFlightInfo(ticket);
                        currTicket.Seats = ticket.AvailiableSeats.ToString();
                        searchList.Add(currTicket);
                    }
                }
            }
            ServerData.ticketDataBaseLock.ReleaseReaderLock();
            return searchList;
        }


        public string ReserveTicket(string flight, string date)
        {
            //acquiring writer lock in order to traverse tickets db and change some ticket
            ServerData.ticketDataBaseLock.AcquireWriterLock(Timeout.Infinite);
            foreach (var ticket in ServerData.ticketDataBase)
            {
                if(ticket.Flight.Equals(flight)
                    && ticket.Date.Equals(date))
                {
                    if (ticket.AvailiableSeats > 0)
                    {
                        ticket.ReservedSeats++;
                        string reservationID = ServerData.ReservationID.ToString();
                        ServerData.ReservationDict.Add(reservationID, flight + " " + date);
                        ServerData.ReservationID++;
                        ServerData.ticketDataBaseLock.ReleaseWriterLock();
                        return reservationID;
                    }else
                    {
                        ServerData.ticketDataBaseLock.ReleaseWriterLock();
                        throw new FaultException("Failed, no seats available");
                    }
                }
            }
            ServerData.ticketDataBaseLock.ReleaseWriterLock();
            throw new FaultException("Failed, no such flight");
        }


        public void CancelTicket(string reservationID)
        {
            //acquiring writer lock in order to traverse tickets db and change some ticket
            ServerData.ticketDataBaseLock.AcquireWriterLock(Timeout.Infinite);
            if (ServerData.ReservationDict.Keys.Contains(reservationID))
            {
                var flight = ServerData.ReservationDict[reservationID].Split(' ')[0];
                var date = ServerData.ReservationDict[reservationID].Split(' ')[1];
                //if reservation for a flight exists then some ticket should have same date and id
                //otherwise, server is in inconcictent state. Should never happen.
                foreach (var ticket in ServerData.ticketDataBase)
                {
                    if (ticket.Flight.Equals(flight)
                        && ticket.Date.Equals(date))
                    {
                        ticket.ReservedSeats--;
                        ServerData.ReservationDict.Remove(reservationID);
                        ServerData.ticketDataBaseLock.ReleaseWriterLock();
                        return;
                    }
                }
            }
            else
            {
                ServerData.ticketDataBaseLock.ReleaseWriterLock();
                throw new FaultException("Failed, no such reservation");
            }
        }
    }
}
